import {
    event as d3_event,
    select as d3_select,
    selectAll as d3_selectAll
} from 'd3-selection';

import { t, textDirection } from '../util/locale';
import { geoMetersToOffset, geoOffsetToMeters } from '../geo';
import { svgIcon } from '../svg/icon';
import { uiDisclosure } from './disclosure';


export function uiBackgroundOffset(context) {
    var directions = [
        ['right', [0.5, 0]],
        ['top', [0, -0.5]],
        ['left', [-0.5, 0]],
        ['bottom', [0, 0.5]]
    ];


    function d3_eventCancel() {
        d3_event.stopPropagation();
        d3_event.preventDefault();
    }


    function updateValue() {
        var meters = geoOffsetToMeters(context.background().offset());
        var x = +meters[0].toFixed(2);
        var y = +meters[1].toFixed(2);

        d3_selectAll('.nudge-inner-rect')
            .select('input')
            .classed('error', false)
            .property('value', x + ', ' + y);

        d3_selectAll('.nudge-reset')
            .classed('disabled', function() {
                return (x === 0 && y === 0);
            });
    }


    function resetOffset() {
        context.background().offset([0, 0]);
        updateValue();
    }


    function nudge(d) {
        context.background().nudge(d, context.map().zoom());
        updateValue();
    }


    function clickNudgeButton(d) {
        var interval;
        var timeout = window.setTimeout(function() {
                interval = window.setInterval(nudge.bind(null, d), 100);
            }, 500);

        function doneNudge() {
            window.clearTimeout(timeout);
            window.clearInterval(interval);
            d3_select(window)
                .on('mouseup.buttonoffset', null, true)
                .on('mousedown.buttonoffset', null, true);
        }

        d3_select(window)
            .on('mouseup.buttonoffset', doneNudge, true)
            .on('mousedown.buttonoffset', doneNudge, true);

        nudge(d);
    }


    function inputOffset() {
        var input = d3_select(this);
        var d = input.node().value;

        if (d === '') return resetOffset();

        d = d.replace(/;/g, ',').split(',').map(function(n) {
            // if n is NaN, it will always get mapped to false.
            return !isNaN(n) && n;
        });

        if (d.length !== 2 || !d[0] || !d[1]) {
            input.classed('error', true);
            return;
        }

        context.background().offset(geoMetersToOffset(d));
        updateValue();
    }


    function dragOffset() {
        if (d3_event.button !== 0) return;

        var origin = [d3_event.clientX, d3_event.clientY];

        context.container()
            .append('div')
            .attr('class', 'nudge-surface');

        d3_select(window)
            .on('mousemove.offset', function() {
                var latest = [d3_event.clientX, d3_event.clientY];
                var d = [
                    -(origin[0] - latest[0]) / 4,
                    -(origin[1] - latest[1]) / 4
                ];

                origin = latest;
                nudge(d);
            })
            .on('mouseup.offset', function() {
                if (d3_event.button !== 0) return;
                d3_selectAll('.nudge-surface')
                    .remove();

                d3_select(window)
                    .on('mousemove.offset', null)
                    .on('mouseup.offset', null);
            });
    }


    function render(selection) {
        var container = selection.selectAll('.nudge-container')
            .data([0]);

        var containerEnter = container.enter()
            .append('div')
            .attr('class', 'nudge-container cf');

        containerEnter
            .append('div')
            .attr('class', 'nudge-instructions')
            .text(t('background.offset'));

        var nudgeEnter = containerEnter
            .append('div')
            .attr('class', 'nudge-outer-rect')
            .on('mousedown', dragOffset);

        nudgeEnter
            .append('div')
            .attr('class', 'nudge-inner-rect')
            .append('input')
            .on('change', inputOffset);

        containerEnter
            .append('div')
            .selectAll('button')
            .data(directions).enter()
            .append('button')
            .attr('class', function(d) { return d[0] + ' nudge'; })
            .on('contextmenu', d3_eventCancel)
            .on('mousedown', function(d) {
                if (d3_event.button !== 0) return;
                clickNudgeButton(d[1]);
            });

        containerEnter
            .append('button')
            .attr('title', t('background.reset'))
            .attr('class', 'nudge-reset disabled')
            .on('contextmenu', d3_eventCancel)
            .on('click', function() {
                if (d3_event.button !== 0) return;
                resetOffset();
            })
            .call(svgIcon('#iD-icon-' + (textDirection === 'rtl' ? 'redo' : 'undo')));

        updateValue();
    }


    function backgroundOffset(selection) {
        selection
            .call(uiDisclosure(context, 'background_offset', false)
                .title(t('background.fix_misalignment'))
                .content(render)
            );
    }


    context.background()
        .on('change.backgroundOffset-update', updateValue);

    return backgroundOffset;
}
